#include "ramprakash.Part2Common.h"

int sendMsg(int sockfd, char *buf, int size)
{
    if (sendto(sockfd, buf, size, 0, NULL, 0) == -1) 
    {
        perror("sendto");
        return errno;
    }
    return 0;
}

// Get username and password from the user. The password is not echoed on the
// screen and has been tested on linux/macOS X. May not work on Windows and
// might need changes to get the program to compile
int getPass(char *u, char *p)
{
    struct termios old, new;

    printf("Username: ");
    scanf("%s", u);
    printf("Password: ");
    /* Turn echoing off and fail if we can't. */
    if (tcgetattr (fileno (stdin), &old) != 0) {
        perror("tcgetattr");
        return -1;
    }
    new = old;
    new.c_lflag &= ~ECHO;
    if (tcsetattr (fileno (stdin), TCSAFLUSH, &new) != 0) {
        perror("tcsetattr");
        return -1;
    }

    /* Read the password. */
    scanf("%s", p);

    /* Restore terminal. */
    (void) tcsetattr (fileno (stdin), TCSAFLUSH, &old);
    printf("\n");

    return 0;
}

// Uses DEC ECB mode encryption from the OpenSSL library to encrypt buf of
// length len and the ciphertext is placed in rb. Note that the ciphertext can
// be longer than the plaintext due to padding. The caller of this function has
// to ensure that rb has sufficient space to hold the complete ciphertext.
int  desCryptM(char *key, char *buf, int len, char *rb, int flag)
{
#ifdef AES
    char *nextInBlock;
    char *nextOutBlock;
    int llen = 0;
    unsigned char ibuf[16]; // AES block size 128 bits
    unsigned char obuf[16]; // AES block size 128 bits
    int  adj = 16; // used for adjusting the buffer for padding
    AES_KEY aes_key;

    nextInBlock  = buf;
    nextOutBlock = rb;
    if (flag) {
        AES_set_encrypt_key((const unsigned char *)key, 128, &aes_key);
    } else {
        AES_set_decrypt_key((const unsigned char *)key, 128, &aes_key);
    }

    while (llen < len) {
        memset(ibuf, 0, sizeof(ibuf));
        if ((llen + 16) > len) {
            // last block - copy the remaining bytes only. rest of the bytes
            // are already 0 due to the memset above
            adj = len - llen;
        }
        memcpy(ibuf, nextInBlock, adj);
        AES_ecb_encrypt(ibuf, obuf, &aes_key, flag);
        memcpy(nextOutBlock, obuf, 16);
        nextInBlock += 16;
        nextOutBlock += 16;
        llen += 16;
    }
    return llen;
#else
    char *nextInBlock;
    char *nextOutBlock;
    unsigned char lbuf[8]; // DES block size 64 bits
    int  llen = 0;
    int  rv;
    int  adj = 8; // used for adjusting the buffer for padding
    des_key_schedule ks;

    DES_set_odd_parity((DES_cblock *)key);
    if ((rv = des_set_key_checked((DES_cblock *)key, ks)) != 0)
    {
        // No use carrying on
        printf("Key error\n");
        exit(1);
    }

    nextInBlock  = buf;
    nextOutBlock = rb;
    while (llen < len) {
        // This automatically takes care of padding with 0
        memset(lbuf, 0, sizeof(lbuf));
        if ((llen + 8) > len) {
            // last block - copy the remaining bytes only. rest of the bytes
            // are already 0 due to the memset above
            adj = len - llen;
        }
        memcpy(lbuf, nextInBlock, adj);
        des_encrypt1((unsigned int *)lbuf, ks, flag);
        memcpy(nextOutBlock, lbuf, 8);
        nextInBlock += 8;
        nextOutBlock += 8;
        llen += 8;
    }
    return llen;
#endif
}

// Be careful while calling this function. No validations for the pointer.
// All validations are assumed to be done by the caller
void cryptM(char *k, char *m, int len, char *rb, int flag)
{
    int keylen = strlen(k);
    int i = 0;
    int j = 0;
    if (flag) {
        //LOG("Encrypted Plaintext M(%d): %s with key: %s\n", len, m, k);
        while(i < len) {
            rb[i] = m[i] ^ k[j];
            j++;
            i++;
            if (j == keylen)
                j = 0;
        }
    } else {
        while(i < len) {
            rb[i] = m[i] ^ k[j];
            j++;
            i++;
            if (j == keylen)
                j = 0;
        }
        //LOG("Decrypted Plaintext M(%d): %s with key: %s\n", len, rb, k);
    }
}

int getRandom()
{
    struct timeval tv;

    if (gettimeofday(&tv, NULL) < 0) {
        LOG("gettimeofday failed");
    }

    return tv.tv_usec;
}

// Calculate the SHA-1 digest for a file and store it in digest.
// The size of memory for digest is assumed to be atleast 20 bytes
void sha1Digest(char *file, unsigned char *digest)
{
    SHA_CTX c;
    FILE *fd;
    unsigned char buf[1024];
    int  buflen;

    fd = fopen(file, "r");
    SHA1_Init(&c);
    while ((buflen = fread(buf, 1, 1024, fd))) {
        SHA1_Update(&c, buf, buflen);
    }
    SHA1_Final(digest, &c);
}

